
#ifndef NOSAL_EXEC_INTERNAL_DEPENDENCY_CALCULATOR_H
#define NOSAL_EXEC_INTERNAL_DEPENDENCY_CALCULATOR_H

#include "startup_configuration.h"
#include "function_group.h"

namespace netaos {
namespace nosal {
namespace exec {
namespace internal {

/// @brief The TransitionChanges struct contains two lists,
/// one with processes to start, one with process to terminate.
struct TransitionChanges
{
    std::vector<std::shared_ptr<StartupConfiguration>> toStart_;
    std::vector<std::shared_ptr<StartupConfiguration>> toTerminate_;
};

/// @brief The DependencyCalculator
class DependencyCalculator final
{
public:
    /// @brief Constructor.
    DependencyCalculator() = default;

    /// @brief Deleted Copy Constructor.
    DependencyCalculator(const DependencyCalculator&) = delete;

    /// @brief Deleted copy assignment operator.
    DependencyCalculator& operator=(const DependencyCalculator&) = delete;

    /// @brief Deleted move constructor.
    DependencyCalculator(DependencyCalculator&&) = delete;

    /// @brief Deleted move assignment operator.
    DependencyCalculator& operator=(DependencyCalculator&&) = delete;

    /// @brief Defaulted destructor.
    ~DependencyCalculator() = default;

    /// @brief Creates lists of processes to start and to terminate during state transition respecting Execution
    /// Dependencies.
    /// @param[in] list_of_function_groups List of all available FunctionGroups
    /// @param[in] executed_startup_configurations List of all currently executed StartupConfigurations.
    /// @param[in] function_group The FunctionGroup of the transition.
    /// @param[in] state The new state of the FunctionGroup.
    /// @returns TransitionChanges -- list of processes to start and to terminate during state transition.
    TransitionChanges CalculateTransition(const std::map<std::string, FunctionGroup>& list_of_function_groups,
        const std::set<std::shared_ptr<StartupConfiguration>> executed_startup_configurations,
        const FunctionGroup* function_group,
        const std::string& state);

private:
    /// @brief Helper struct for dependency calculation.
    struct DependencyInfo
    {
        std::uint32_t length = 0;
        bool is_calculation_finished = false;
        const StartupConfiguration::DependencyCollectionType& dependencies;
    };

    /// @brief Collection of applications (stringified name) and their Execution Dependency information.
    std::map<std::string, DependencyInfo> dependency_summary_;

    /// @brief Sorts the list of StartupConfigurations according to their Execution Dependencies.
    /// @param[in, out] list_of_applications List of processes to be sorted.
    void SortByDependency(std::vector<std::shared_ptr<StartupConfiguration>>& list_of_applications);

    /// @brief Helper method for ExecutionDependency calculation
    /// @param process_name Name of the application
    /// @returns 32bit integer representing the dependency length
    std::uint32_t CalcDependencyLength(const std::string& process_name);
};

}  // namespace internal
}  // namespace exec
}  // namespace nosal
}  // namespace netaos

#endif  // NOSAL_EXEC_INTERNAL_DEPENDENCY_CALCULATOR_H
